package com.wxl.common.serialport

import android.os.Handler
import android.os.Looper
import android.os.Message
import android.text.TextUtils
import androidx.work.ExistingWorkPolicy
import androidx.work.ListenableWorker
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import com.sdk.DeviceManager_LXR5000.Detonator
import com.vi.vioserial.listener.OnSerialDataListener
import com.vi.vioserial.util.Logger
import com.wxl.common.AppConstant
import com.wxl.common.AppContext
import com.wxl.common.util.Loog
import com.wxl.common.util.ObservableUtil
import com.wxl.common.util.Toll
import io.reactivex.Observable
import io.reactivex.ObservableOnSubscribe
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import java.util.concurrent.TimeUnit

class SerialPortManager {

    private constructor()

    companion object {

        private var mDisposable: Disposable? = null
        private var request: OneTimeWorkRequest? = null

        private var mHandler: Handler? = null
        private const val REVICER_WAHT = 3456

        interface OpenPortCallback {
            /**
             * 打开串口回调
             */
            fun onOpenPort(state: Int)
        }

        /**
         * 打开串口
         */
        fun open(callback: OpenPortCallback) {
            Logger.SHOW_LOG = AppConstant.debug
            openPower(callback,false)
        }


        /**
         * 打开串口，不做其他操作
         */
        fun openOnlyPort(callback: OpenPortCallback){
            Logger.SHOW_LOG = AppConstant.debug
            openPower(callback,true)
        }


        /**
         * 打开串口
         */
        fun open() {
            open(object : OpenPortCallback {
                override fun onOpenPort(success: Int) {

                }
            })
        }


        /**
         * 下电
         */
         fun closePower() {
            ObservableUtil.doNext(ObservableOnSubscribe<Int> {
                val powerOn = Detonator.poweron(5, 0)
                it.onNext(powerOn)
            }, object : ObservableUtil.Companion.OnNextCallback<Int>() {
                override fun onNext(t: Int) {
                    when (t) {
                        0 -> {
                            Loog.e("下电成功。")
                        }
                        else -> {
                            Loog.e("下电失败(code:$t)。")
                        }
                    }
                }
            })
        }

        /***
         * 上电
         */
        private fun openPower(callback: OpenPortCallback,isOnly:Boolean) {
            Observable.create(ObservableOnSubscribe<Int>() {
                val powerOn = Detonator.poweron(5, 1)
                it.onNext(powerOn)
            })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(object : Observer<Int> {
                    override fun onComplete() {

                    }

                    override fun onSubscribe(d: Disposable) {

                    }

                    override fun onNext(t: Int) {
                        if (t == 0) {
                            Loog.e("打开底板电源成功")
                            /**
                             * 打开串口
                             * @param portStr   串口号
                             * @param ibaudRate 波特率
                             *
                             * @return 0：打开串口成功
                             *        -1：无法打开串口：没有串口读/写权限！
                             *        -2：无法打开串口：未知错误！
                             *        -3：无法打开串口：参数错误！
                             */
                            val state = BlastSerial.instance()!!.open("/dev/ttyS6", 57600)
                            AppContext.appContext.saveOpenPortState(state == 0)
                            if (state != 0) {
                                Toll.toll("无法打开串口")
                                close()
                                callback.onOpenPort(state)
                            } else {
                                createHandler()
                                observer()

                                //exitUpdateControl(callback)
                                if(!isOnly) {
                                    clearOutSerialPort(callback)
                                } else {
                                    callback.onOpenPort(state)
                                }
                            }
                        } else {
                            Toll.toll("无法打开底板电源")
                            close()
                            callback.onOpenPort(t)
                        }
                    }

                    override fun onError(e: Throwable) {
                        close()
                        callback.onOpenPort(-2)
                    }
                })
        }


        /**
         * 清除串口占用状态
         */
        fun clearOutSerialPort(callback: OpenPortCallback?) {
            Serials.registerSingleStartHexSerial(SerialCode.CODE_COLLECTOR_SGIN_OUT,
                object : Serial() {
                    override fun loadReceiveData(data: String) {
                        callback?.onOpenPort(0)
                        startIntervalQueryPort(QueryPortJobWork::class.java)
                    }
                })
            send(SerialCmd.CODE_SIGN_OUT)
        }


        private fun exitUpdateControl(callback: OpenPortCallback){
            Serials.registerSingleStartHexSerial(SerialCode.CODE_COLLECTOR_DETONATOR_UPDATE_EXIT,object : Serial(){
                override fun loadReceiveData(data: String) {
                    AppContext.appContext.saveDetonatorVersion(0)
                    clearOutSerialPort(callback)
                }
            })
            send(SerialCmd.OUT_UPGRADE_LEFT + SerialCmd.mQBQType + SerialCmd.OUT_UPGRADE_RIGHT + SerialUtil.getCurrentDetonatorNum(26))
        }

        /**
         * 开启轮询任务
         */
        fun startQueryPortWork() {
            startIntervalQueryPort(QueryPortJobWork::class.java)
        }

        /**
         * 创建handler
         */
        private fun createHandler() {
            mHandler = object : Handler(Looper.getMainLooper()) {
                override fun handleMessage(msg: Message) {
                    super.handleMessage(msg)
                    if (msg.what == REVICER_WAHT) {
                        val hexData = msg.obj as String
                        Serials.loadSerial(hexData)
                    }
                }
            }
        }


        /**
         * 关闭串口
         */
        fun close() {
            cancelIntervalWork()
            BlastSerial.instance()!!.close()
        }

        /**
         * 发送数据
         */
        fun send(data: String) {
            /**
             * 注意发送的数据类型为hex，字符串需要转成hex在发送
             * 转换方法：SerialDataUtils.stringToHexString(String s)
             * @param hexData 发送的数据
             */
            if(AppContext.appContext.isOpenPort()) {
                BlastSerial.instance()!!.sendData(data)
            } else {
                openPower(object : OpenPortCallback{
                    override fun onOpenPort(state: Int) {
                        if(state == 0) {
                            BlastSerial.instance()!!.sendData(data)
                        }
                    }
                },true)
            }
        }

        /**
         * 发送不需要转码的数据
         */
        fun sendHexData(hexData: String){
            if(AppContext.appContext.isOpenPort()) {
                BlastSerial.instance()!!.sendHex(hexData)
            }else {
                openPower(object : OpenPortCallback{
                    override fun onOpenPort(state: Int) {
                        if(state == 0) {
                            BlastSerial.instance()!!.sendHex(hexData)
                        }
                    }
                },true)
            }
        }


        /**
         * 注册串口接收监听
         */
        private fun observer() {
            BlastSerial.instance()?.clearAllDataListener()
            BlastSerial.instance()?.setSerialDataListener(object : OnSerialDataListener {
                override fun onSend(hexData: String?) {
                    //val data = SerialDataUtils.hexStringToString(hexData)
                    // Loog.e("onSend:$hexData")
                }

                override fun onReceive(hexData: String?) {
                    // val data = SerialDataUtils.hexStringToString(hexData)
                    // Loog.e("onReceive:$hexData")
                }

                override fun onReceiveFullData(hexData: String?) {
                    //  val data = SerialDataUtils.hexStringToString(hexData)
                    Loog.e("receiveData:$hexData")
                    if (!TextUtils.isEmpty(hexData)) {
                        val message = Message.obtain()
                        message.what = REVICER_WAHT
                        message.obj = hexData
                        mHandler?.sendMessage(message)
                    }
                }

            })
        }


        /**
         * 轮询串口状态
         */
        internal fun <T : ListenableWorker> startIntervalQueryPort(workerClass: Class<T>) {
            cancelIntervalWork()
            mDisposable = Observable.timer(1500, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.newThread())
                .subscribe(Consumer {
                    request = OneTimeWorkRequest.Builder(workerClass).build()
                    WorkManager.getInstance(AppContext.appContext.getApplication())
                        .beginUniqueWork("unique", ExistingWorkPolicy.REPLACE, request!!)
                        .enqueue()
                })
        }


        /**
         * 取消，清除当前任务
         */
        fun cancelIntervalWork() {
            if (request != null) {
                WorkManager.getInstance(AppContext.appContext.getApplication())
                    .cancelWorkById(request!!.id)
            }
            mDisposable?.dispose()
        }

        /**
         * 停止轮询串口
         */
        internal fun stopIntervalQueryPort() {
            WorkManager.getInstance(AppContext.appContext.getApplication()).cancelAllWork()
            mDisposable?.dispose()
            mHandler?.removeCallbacksAndMessages(0)
        }

    }


}